
#define MIN_REFLECTIVITY 0.04
#define PI 3.1415926535898

#include "Shadow.glh"
#include "Light.glh"
#include "MVPAndViewPos.glh"


vec3 fresnelSchlick(float vdoth /*cosTheta*/,vec3 f){
  return f + (1.0 - f) * pow(1.0 - vdoth,5.0);
}

float distributionGGX(float ndoth, float roughness)
{
    float a      = roughness*roughness;
    float a2     = a*a;
    float ndoth2 = ndoth*ndoth;
    float nom   = a2;
    float denom = (ndoth2 * (a2 - 1.0) + 1.0);
    denom = PI * denom * denom;

    return nom / denom;
}

float geometrySchlickGGX(float ndotv, float roughness)
{
    float r = (roughness + 1.0);
    float k = (r*r) / 8.0;

    float nom   = ndotv;
    float denom = ndotv * (1.0 - k) + k;

    return nom / denom;
}
float geometrySmith(float ndotv, float ndotl, float roughness)
{
    float ggx2  = geometrySchlickGGX(ndotv, roughness);
    float ggx1  = geometrySchlickGGX(ndotl, roughness);
    return ggx1 * ggx2;
}

vec3 calculateLightPbr(vec3 toLight,vec3 normal,vec3 toView,vec3 albedo, vec3 radiance /* already attenuation */ , float metallic,float roughness){
    vec3 f0 = mix(vec3(MIN_REFLECTIVITY),albedo,metallic);
    vec3 halfDir = normalize(toLight + toView);

    float ndoth = max(dot(normal,halfDir),0.0);
    float ndotv = max(dot(normal,toView),0.0);
    float ndotl = max(dot(normal,toLight),0.0);
    float vdoth = max(dot(toView,halfDir),0.0);

    vec3 f = fresnelSchlick(vdoth,f0);
    float d = geometrySmith(ndotv,ndotl,roughness);
    float n = distributionGGX(ndoth,roughness);
    vec3 spec = f * d * n / (4 * ndotv * ndotl + 0.0001) ;
    vec3 ks = f;
    vec3 kd = 1.0 - ks;
    kd *= 1.0 - metallic;
    return (kd * albedo / PI + spec) * radiance * ndotl;
}

vec3 calculateDirectionalLight(DirectionalLight d,vec3 toView,vec3 normal,vec3 color,float metallic,float roughness){
  vec3 toLight = -d.direction.xyz;
  float ndotl = max(dot(normal,toLight),0.0);
  vec3 radiance = d.colorAndIntensity.rgb * ndotl * d.colorAndIntensity.a;
  return calculateLightPbr(toLight,normal,toView,color,radiance,metallic,roughness);
}

in ShaderData{
  vec3 worldPos;
  vec3 worldNormal;
  vec2 fragUv;
} fs_in;

uniform vec3 color;
uniform sampler2D colorMap;
uniform float metallic;
uniform float roughness;
out vec4 fragColor;


void main(){  
    
    vec3 color = texture(colorMap,fs_in.fragUv).rgb;
    vec3 viewDir = normalize(viewPos - fs_in.worldPos);

    vec3 outputColor = vec3(0.0);
    for(int i = 0;i<directionalLightCount;++i){
        if(i == 0){
            bool oc = false;
#ifdef USE_SHADOWMAP
oc = isOcclude(fs_in.worldPos);
#endif

#ifdef USE_CASCADED_SHADOWMAP
oc = isOccludeCascade(fs_in.worldPos,viewMatrix);
#endif
            //暂时让它全黑下来
            outputColor += calculateDirectionalLight(directionalLights[i],viewDir,fs_in.worldNormal,color,metallic,roughness) * int(!oc);
        }else{
            outputColor += calculateDirectionalLight(directionalLights[i],viewDir,fs_in.worldNormal,color,metallic,roughness);
        }
    }

    fragColor = vec4(outputColor + color  * ambientColor.xyz ,1.0f);
}